package symbol;
import java.util.*;
import translationTable.Method;

public class SymbolTable {
		
    private final Map<String,SymbolTableEntry> symbols = new HashMap<String, SymbolTableEntry>();

    private static SymbolTable instance;

    private String currentId;

    private int currentInstr = 0;

    private ObjectState lastObjectState;
    
    private String parentType;
    
    
    private final Map<Integer,Integer> instructionFromMethodMap;
    private String className;
    //First Integer : key ,  Second Integer is the number of MethodeDescription
    
    private ArrayList<Method> methodsDescriptions;

    public ArrayList<Method> getMethodsDescriptions() {
        return methodsDescriptions;
    }

    public void setMethodsDescriptions(ArrayList<Method> methodsDescriptions) {
        this.methodsDescriptions = methodsDescriptions;
    }

    /**
        */
    private SymbolTable() {
        this.instructionFromMethodMap = new HashMap<Integer, Integer>();
        this.methodsDescriptions = new ArrayList<Method>();
    }

    public static SymbolTable getInstance(){
        if (null == instance) { // Premier appel
            instance = new SymbolTable();
        }
        return instance;
    }
    
    public HashMap<Integer, Integer> getInstructionFromMethodMap(){
        return (HashMap<Integer, Integer>) this.instructionFromMethodMap;
    }
    
    public ArrayList<Method> getMethodsDescription(){
        return this.methodsDescriptions;
    }
    
    public ObjectState getLastObjectState() {
        return lastObjectState;
    }

    public void setLastObjectState(ObjectState lastObjectState) {
        this.lastObjectState = lastObjectState;
    }

    public int getCurrentInstr() {
        return currentInstr;
    }

    public void setCurrentInstr(int currentInstr) {
        this.currentInstr = currentInstr;
    }

    public void incrCurrentInstr(){
        ++this.currentInstr;        
    }

    public String getCurrentId() {
        return currentId;
    }

    public void setCurrentId(String currentId){
        this.currentId = currentId;        
    }

    public String getParentType() {
        return parentType;
    }

    public void setParentType(String parentType) {
        this.parentType = parentType;
    }
    
    /** 
        * Add a symbol in the table.
    */
    public void add(String identifier, SymbolTableEntry entry) {        
        this.symbols.put(identifier, entry);
    }

    /** Return the entry for the given lexeme.
        * 
        * @param lexeme
        * @return the entry, or <code>null</code> if not found.
        */
    public SymbolTableEntry get(String lexeme) {
            if (lexeme==null || lexeme.isEmpty()) return null;
            return this.symbols.get(lexeme);
    }

    public HashMap<String,SymbolTableEntry> getAll(){
        return (HashMap<String, SymbolTableEntry>) this.symbols;
    }

    /** Return if the given lexeme is defined in the symbol table.
        * 
        * @param lexeme
        * @return the entry, or <code>null</code> if not found.
        */
    public boolean contains(String lexeme) {
            if (lexeme==null || lexeme.isEmpty()) return false;
            return this.symbols.containsKey(lexeme);
    }

    /** Clear the symbol table.
        */
    public void clear() {
            this.symbols.clear();
    }

    /**
        * {@inheritDoc}
        */
    @Override
    public  String toString() {
            StringBuilder b = new StringBuilder();
            for(SymbolTableEntry entry : this.symbols.values()) {
                    if (b.length()>0) {
                            b.append("\n"); //$NON-NLS-1$
                    }
                    b.append(entry.toString());
            }
            b.append("\n parentType="+this.parentType);
            return b.toString();
    }
    
    public void addMethodeDescription(Method myMethode){
        methodsDescriptions.add(myMethode);
    }
    
    public void addCorrespondanceMethodeInstruction(Integer instruction, Integer indMethodeDescription) throws Exception{
        try{
            instructionFromMethodMap.put(instruction, indMethodeDescription);
            
        }
        catch(Exception e){
             throw new Exception("Ajout Instruction et indice methode erreur");
        }
    }
    
        /**
         * 
         * @param m Methode Description
         
         * @return -1 si 'existe pas sinon retourne l'indexe dans la liste de methodeDescription
         */
    public Method getMethodeDescription(int numeroInstruction) throws Exception{
            try{ int numListe = instructionFromMethodMap.get(numeroInstruction);
                Method methode = methodsDescriptions.get(numListe);
                return methode;
            }
        catch(Exception e){
             throw new Exception("La numéro d'instruction ne correspond a aucune methode dans la liste");
        }
        
    }

    public String getClassName() {
        return this.className;
    }
    
    public void setClassName(String className){
        this.className = className;
    }
}